<template>
  <div class="url-encoder">
    <button @click="returnFn" class="btn btn-primary retrunBUtton">
      <i class="icon">⚡</i> 返回
    </button>
    <div class="container">
      <header class="tool-header">
        <h1>URL 编码/解码工具</h1>
        <p class="subtitle">在线进行URL编码和解码操作，支持批量处理</p>
      </header>

      <div class="tool-content">
        <!-- 输入区域 -->
        <div class="input-section">
          <div class="input-group">
            <label for="inputText">输入文本：</label>
            <textarea
              id="inputText"
              v-model="inputText"
              placeholder="输入需要编码或解码的URL或文本..."
              rows="6"
              class="text-input"
              spellcheck="false"
            ></textarea>
          </div>

          <div class="action-buttons">
            <button @click="encodeURL" class="encode-btn" :disabled="!inputText">🔒 编码URL</button>
            <button @click="decodeURL" class="decode-btn" :disabled="!inputText">🔓 解码URL</button>
            <button @click="clearAll" class="clear-btn">🗑️ 清空</button>
          </div>
        </div>

        <!-- 输出区域 -->
        <div class="output-section">
          <div class="output-header">
            <label>处理结果：</label>
            <div class="output-actions">
              <button @click="copyResult" class="copy-btn" :disabled="!outputText">
                {{ copyButtonText }}
              </button>
              <button @click="toggleView" class="toggle-btn">
                {{ showDetails ? '隐藏详情' : '显示详情' }}
              </button>
            </div>
          </div>
          <textarea
            v-model="outputText"
            readonly
            rows="6"
            class="result-input"
            placeholder="编码或解码结果将显示在这里..."
            spellcheck="false"
          ></textarea>
        </div>

        <!-- 详情面板 -->
        <div v-if="showDetails && outputText" class="details-section">
          <h3>编码详情</h3>
          <div class="details-grid">
            <div class="detail-item">
              <span class="detail-label">原始长度：</span>
              <span class="detail-value">{{ inputText.length }} 字符</span>
            </div>
            <div class="detail-item">
              <span class="detail-label">结果长度：</span>
              <span class="detail-value">{{ outputText.length }} 字符</span>
            </div>
            <div class="detail-item">
              <span class="detail-label">长度变化：</span>
              <span class="detail-value" :class="getLengthChangeClass()">
                {{ getLengthChange() }}
              </span>
            </div>
            <div class="detail-item">
              <span class="detail-label">编码字符数：</span>
              <span class="detail-value">{{ encodedCharsCount }} 个</span>
            </div>
          </div>

          <div class="characters-section">
            <h4>编码字符对照表</h4>
            <div class="characters-grid">
              <div v-for="char in encodedCharacters" :key="char.original" class="char-item">
                <span class="char-original">{{ formatChar(char.original) }}</span>
                <span class="char-arrow">→</span>
                <span class="char-encoded">{{ char.encoded }}</span>
              </div>
            </div>
          </div>
        </div>

        <!-- 选项设置 -->
        <div class="options-section">
          <h3>编码选项</h3>
          <div class="options-grid">
            <div class="option-group">
              <label class="checkbox-label">
                <input type="checkbox" v-model="options.encodeAll" />
                <span class="checkmark"></span>
                编码所有字符
              </label>
              <small>包括字母和数字（通常不需要）</small>
            </div>

            <div class="option-group">
              <label class="checkbox-label">
                <input type="checkbox" v-model="options.preserveSpaces" />
                <span class="checkmark"></span>
                空格编码为+号
              </label>
              <small>否则编码为%20</small>
            </div>

            <div class="option-group">
              <label class="checkbox-label">
                <input type="checkbox" v-model="options.autoDetect" />
                <span class="checkmark"></span>
                自动检测编码状态
              </label>
              <small>自动判断需要编码还是解码</small>
            </div>

            <div class="option-group">
              <label>编码类型：</label>
              <select v-model="options.encodingType">
                <option value="encodeURI">encodeURI</option>
                <option value="encodeURIComponent">encodeURIComponent</option>
                <option value="custom">自定义编码</option>
              </select>
              <small v-if="options.encodingType === 'encodeURI'">保留URL完整结构</small>
              <small v-else-if="options.encodingType === 'encodeURIComponent'"
                >编码所有特殊字符</small
              >
              <small v-else>自定义编码规则</small>
            </div>
          </div>
        </div>

        <!-- 示例区域 -->
        <div class="examples-section">
          <h3>使用示例</h3>
          <div class="examples-grid">
            <div class="example-item">
              <div class="example-title">普通URL编码</div>
              <div class="example-content">
                <div class="example-before">https://example.com/搜索?q=hello world</div>
                <div class="example-after">
                  https://example.com/%E6%90%9C%E7%B4%A2?q=hello%20world
                </div>
              </div>
              <button @click="loadExample(0)" class="example-btn">使用此示例</button>
            </div>

            <div class="example-item">
              <div class="example-title">参数值编码</div>
              <div class="example-content">
                <div class="example-before">name=张三&age=20&city=北京</div>
                <div class="example-after">
                  name=%E5%BC%A0%E4%B8%89&age=20&city=%E5%8C%97%E4%BA%AC
                </div>
              </div>
              <button @click="loadExample(1)" class="example-btn">使用此示例</button>
            </div>

            <div class="example-item">
              <div class="example-title">特殊字符编码</div>
              <div class="example-content">
                <div class="example-before">!@#$%^&*(){}[]=+</div>
                <div class="example-after">%21%40%23%24%25%5E%26*()%7B%7D%5B%5D%3D%2B</div>
              </div>
              <button @click="loadExample(2)" class="example-btn">使用此示例</button>
            </div>
          </div>
        </div>

        <!-- 信息说明 -->
        <div class="info-section">
          <h3>URL编码说明</h3>
          <div class="info-content">
            <p>
              <strong>URL编码</strong
              >（百分比编码）是将URL中不允许的字符转换为%后跟两位十六进制数的格式。
            </p>
            <p>
              <strong>encodeURI()</strong>：用于编码完整的URL，不会对:/?#[]@!$&'()*+,;=等字符编码。
            </p>
            <p><strong>encodeURIComponent()</strong>：用于编码URL参数，会对更多字符进行编码。</p>
            <p>通常建议使用encodeURIComponent()来编码URL参数值。</p>
          </div>
        </div>
      </div>

      <footer class="tool-footer">
        <p>© 2023 Vue 3 URL编码工具</p>
      </footer>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch } from 'vue'
import { useRouter } from 'vue-router'
const inputText = ref('')
const outputText = ref('')
const showDetails = ref(false)
const copyButtonText = ref('复制结果')
const encodedCharacters = ref([])
const lastOperation = ref('') // 'encode' or 'decode'
const Router = useRouter()
const returnFn = () => {
  Router.go(-1)
}
const options = ref({
  encodeAll: false,
  preserveSpaces: true,
  autoDetect: true,
  encodingType: 'encodeURIComponent'
})

const examples = [
  {
    input: 'https://example.com/搜索?q=hello world',
    output: 'https://example.com/%E6%90%9C%E7%B4%A2?q=hello%20world',
    description: '普通URL编码'
  },
  {
    input: 'name=张三&age=20&city=北京',
    output: 'name=%E5%BC%A0%E4%B8%89&age=20&city=%E5%8C%97%E4%BA%AC',
    description: '参数值编码'
  },
  {
    input: '!@#$%^&*(){}[]=+',
    output: '%21%40%23%24%25%5E%26*()%7B%7D%5B%5D%3D%2B',
    description: '特殊字符编码'
  }
]

// 编码URL
const encodeURL = () => {
  if (!inputText.value.trim()) {
    outputText.value = ''
    return
  }

  try {
    let result = ''

    if (options.value.encodeAll) {
      // 编码所有字符
      result = customEncodeAll(inputText.value)
    } else {
      switch (options.value.encodingType) {
        case 'encodeURI':
          result = encodeURI(inputText.value)
          break
        case 'encodeURIComponent':
          result = encodeURIComponent(inputText.value)
          break
        case 'custom':
          result = customEncode(inputText.value)
          break
      }
    }

    // 处理空格
    if (options.value.preserveSpaces) {
      result = result.replace(/%20/g, '+')
    }

    outputText.value = result
    lastOperation.value = 'encode'
    analyzeEncoding()
  } catch (error) {
    outputText.value = '编码出错：' + error.message
  }
}

// 解码URL
const decodeURL = () => {
  if (!inputText.value.trim()) {
    outputText.value = ''
    return
  }

  try {
    let textToDecode = inputText.value

    // 处理+号空格
    if (options.value.preserveSpaces) {
      textToDecode = textToDecode.replace(/\+/g, '%20')
    }

    const result = decodeURIComponent(textToDecode)
    outputText.value = result
    lastOperation.value = 'decode'
    analyzeEncoding()
  } catch (error) {
    // 如果decodeURIComponent失败，尝试decodeURI
    try {
      const result = decodeURI(inputText.value)
      outputText.value = result
      lastOperation.value = 'decode'
      analyzeEncoding()
    } catch (error2) {
      outputText.value = '解码出错：URL格式不正确'
    }
  }
}

// 自定义编码（更严格的编码）
const customEncode = (text) => {
  return encodeURIComponent(text)
    .replace(/!/g, '%21')
    .replace(/'/g, '%27')
    .replace(/\(/g, '%28')
    .replace(/\)/g, '%29')
    .replace(/\*/g, '%2A')
}

// 编码所有字符
const customEncodeAll = (text) => {
  let result = ''
  for (let i = 0; i < text.length; i++) {
    const char = text.charAt(i)
    const code = char.charCodeAt(0)
    if (code > 127 || /[^a-zA-Z0-9\-_.~]/.test(char)) {
      result += '%' + code.toString(16).toUpperCase().padStart(2, '0')
    } else {
      result += char
    }
  }
  return result
}

// 分析编码结果
const analyzeEncoding = () => {
  if (lastOperation.value !== 'encode') {
    encodedCharacters.value = []
    return
  }

  const chars = []
  const input = inputText.value
  const output = outputText.value

  let i = 0
  let j = 0

  while (i < input.length && j < output.length) {
    const inputChar = input.charAt(i)

    if (output.charAt(j) === '%' && j + 2 < output.length) {
      const hex = output.substring(j + 1, j + 3)
      const decodedChar = String.fromCharCode(parseInt(hex, 16))

      if (inputChar !== decodedChar) {
        chars.push({
          original: inputChar,
          encoded: '%' + hex
        })
      }

      j += 3
      i++
    } else {
      if (output.charAt(j) !== inputChar) {
        chars.push({
          original: inputChar,
          encoded: output.charAt(j)
        })
      }
      j++
      i++
    }
  }

  encodedCharacters.value = chars
}

// 计算编码字符数量
const encodedCharsCount = computed(() => {
  return encodedCharacters.value.length
})

// 获取长度变化
const getLengthChange = () => {
  const change = outputText.value.length - inputText.value.length
  const sign = change >= 0 ? '+' : ''
  return `${sign}${change} 字符`
}

// 获取长度变化样式类
const getLengthChangeClass = () => {
  const change = outputText.value.length - inputText.value.length
  return change > 0 ? 'positive' : change < 0 ? 'negative' : 'neutral'
}

// 格式化字符显示
const formatChar = (char) => {
  if (char === ' ') return '空格'
  if (char === '\t') return '制表符'
  if (char === '\n') return '换行符'
  if (char === '\r') return '回车符'
  return char
}

// 复制结果
const copyResult = async () => {
  if (!outputText.value) return

  try {
    await navigator.clipboard.writeText(outputText.value)
    copyButtonText.value = '已复制!'
    setTimeout(() => {
      copyButtonText.value = '复制结果'
    }, 2000)
  } catch (err) {
    const textArea = document.createElement('textarea')
    textArea.value = outputText.value
    document.body.appendChild(textArea)
    textArea.select()
    try {
      document.execCommand('copy')
      copyButtonText.value = '已复制!'
      setTimeout(() => {
        copyButtonText.value = '复制结果'
      }, 2000)
    } catch (err2) {
      copyButtonText.value = '复制失败'
      setTimeout(() => {
        copyButtonText.value = '复制结果'
      }, 2000)
    }
    document.body.removeChild(textArea)
  }
}

// 切换详情显示
const toggleView = () => {
  showDetails.value = !showDetails.value
}

// 清空所有
const clearAll = () => {
  inputText.value = ''
  outputText.value = ''
  encodedCharacters.value = []
  lastOperation.value = ''
}

// 加载示例
const loadExample = (index) => {
  if (examples[index]) {
    inputText.value = examples[index].input
    outputText.value = examples[index].output
  }
}

// 自动检测并处理
watch(inputText, (newValue) => {
  if (newValue && options.value.autoDetect) {
    // 简单启发式检测：如果包含%号，可能是已编码的URL
    if (newValue.includes('%') && /%[0-9A-Fa-f]{2}/.test(newValue)) {
      decodeURL()
    } else if (newValue.match(/[^\x00-\x7F]/) || /[<>#%{}|\\^~\[\]`]/.test(newValue)) {
      // 如果包含非ASCII字符或特殊字符，进行编码
      encodeURL()
    }
  }
})

// 监听选项变化，重新处理
watch(options, () => {
  if (inputText.value) {
    if (lastOperation.value === 'encode') {
      encodeURL()
    } else if (lastOperation.value === 'decode') {
      decodeURL()
    }
  }
}, { deep: true })
</script>

<style scoped>
.btn {
  padding: 8px 15px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 20px;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 5px;
  transition: all 0.3s ease;
}

.btn-primary {
  background: linear-gradient(to right, #667eea, #764ba2);
  color: white;
}
.retrunBUtton {
  position: absolute;
  top: 100px;
  right: 100px;
}
.url-encoder {
  min-height: 100vh;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  padding: 20px;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  position: relative;
}

.container {
  max-width: 1000px;
  margin: 0 auto;
  background: white;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}

.tool-header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 30px;
  text-align: center;
  border-radius: 12px 12px 0 0;
}

.tool-header h1 {
  margin: 0 0 10px 0;
  font-size: 2.2em;
}

.subtitle {
  margin: 0;
  opacity: 0.9;
  font-size: 1.1em;
}

.tool-content {
  padding: 30px;
}

.input-section,
.output-section {
  margin-bottom: 30px;
}

.input-group,
.output-header {
  margin-bottom: 15px;
}

.input-group label,
.output-header label {
  display: block;
  font-weight: 600;
  color: #333;
  margin-bottom: 10px;
  font-size: 20px;
}

.output-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.output-actions {
  display: flex;
  gap: 10px;
}

.text-input,
.result-input {
  width: 100%;
  padding: 15px;
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  font-size: 18px;
  font-family: 'Courier New', monospace;
  resize: vertical;
  transition: border-color 0.3s;
  background: #f8f9fa;
  line-height: 1.5;
}

.text-input:focus {
  outline: none;
  border-color: #667eea;
}

.result-input {
  background: #f0f0f0;
  color: #666;
}

.action-buttons {
  display: flex;
  gap: 15px;
  flex-wrap: wrap;
}

.encode-btn,
.decode-btn,
.clear-btn,
.copy-btn,
.toggle-btn {
  padding: 12px 20px;
  border: none;
  border-radius: 6px;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s;
}

.encode-btn {
  background: #4caf50;
  color: white;
}

.encode-btn:hover:not(:disabled) {
  background: #45a049;
  transform: translateY(-2px);
}

.decode-btn {
  background: #2196f3;
  color: white;
}

.decode-btn:hover:not(:disabled) {
  background: #1976d2;
  transform: translateY(-2px);
}

.clear-btn {
  background: #ff9800;
  color: white;
}

.clear-btn:hover {
  background: #f57c00;
  transform: translateY(-2px);
}

.copy-btn {
  background: #9c27b0;
  color: white;
}

.toggle-btn {
  background: #607d8b;
  color: white;
}

button:hover:not(:disabled) {
  transform: translateY(-2px);
}

button:disabled {
  background: #cccccc;
  cursor: not-allowed;
  transform: none !important;
}

.details-section {
  background: #f8f9fa;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 30px;
}

.details-section h3 {
  margin-bottom: 15px;
  color: #333;
}

.details-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 15px;
  margin-bottom: 20px;
}

.detail-item {
  background: white;
  padding: 15px;
  border-radius: 6px;
  border-left: 4px solid #667eea;
}

.detail-label {
  font-weight: 600;
  color: #666;
  display: block;
  font-size: 18px;
}

.detail-value {
  font-size: 1.2em;
  font-weight: 600;
  color: #333;
  display: block;
}

.detail-value.positive {
  color: #f44336;
}

.detail-value.negative {
  color: #4caf50;
}

.detail-value.neutral {
  color: #666;
}

.characters-section h4 {
  margin-bottom: 15px;
  color: #333;
}

.characters-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 10px;
}

.char-item {
  background: white;
  padding: 10px;
  border-radius: 4px;
  text-align: center;
  font-family: 'Courier New', monospace;
  font-size: 20px;
}

.char-original {
  color: #333;
  font-weight: 600;
}

.char-arrow {
  color: #666;
  margin: 0 5px;
}

.char-encoded {
  color: #2196f3;
  font-weight: 600;
}

.options-section {
  background: #f8f9fa;
  padding: 20px;
  border-radius: 8px;
  margin-bottom: 30px;
}

.options-section h3 {
  margin-bottom: 15px;
  color: #333;
}

.options-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}

.option-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.option-group label {
  font-weight: 600;
  color: #555;
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-weight: normal;
}

.checkbox-label input {
  display: none;
}

.checkmark {
  width: 18px;
  height: 18px;
  border: 2px solid #ddd;
  border-radius: 3px;
  position: relative;
  transition: all 0.3s;
}

.checkbox-label input:checked + .checkmark {
  background: #667eea;
  border-color: #667eea;
}

.checkbox-label input:checked + .checkmark::after {
  content: '✓';
  position: absolute;
  color: white;
  font-size: 20px;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

select {
  padding: 8px 12px;
  border: 2px solid #e0e0e0;
  border-radius: 6px;
  font-size: 18px;
  max-width: 200px;
}

small {
  color: #666;
  font-size: 20px;
}

.examples-section {
  margin-bottom: 30px;
}

.examples-section h3 {
  margin-bottom: 15px;
  color: #333;
}

.examples-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
}

.example-item {
  background: #f8f9fa;
  padding: 20px;
  border-radius: 8px;
  border: 1px solid #e0e0e0;
}

.example-title {
  font-weight: 600;
  color: #333;
  margin-bottom: 10px;
}

.example-content {
  margin-bottom: 15px;
}

.example-before,
.example-after {
  font-family: 'Courier New', monospace;
  font-size: 20px;
  padding: 8px;
  background: white;
  border-radius: 4px;
  margin-bottom: 5px;
  word-break: break-all;
}

.example-before {
  color: #666;
}

.example-after {
  color: #2196f3;
}

.example-btn {
  background: #667eea;
  color: white;
  border: none;
  padding: 8px 16px;
  border-radius: 4px;
  font-size: 20px;
  cursor: pointer;
  width: 100%;
}

.example-btn:hover {
  background: #5a6fd8;
}

.info-section {
  background: #e3f2fd;
  border-left: 4px solid #2196f3;
  padding: 20px;
  border-radius: 0 8px 8px 0;
}

.info-section h3 {
  color: #1565c0;
  margin-bottom: 15px;
}

.info-content p {
  color: #424242;
  line-height: 1.6;
  margin-bottom: 10px;
}

.tool-footer {
  text-align: center;
  padding: 20px;
  color: #757575;
  font-size: 18px;
  border-top: 1px solid #e0e0e0;
}

@media (max-width: 768px) {
  .tool-content {
    padding: 20px;
  }

  .action-buttons,
  .output-actions {
    flex-direction: column;
  }

  .details-grid {
    grid-template-columns: 1fr;
  }

  .options-grid,
  .examples-grid {
    grid-template-columns: 1fr;
  }

  .characters-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}
</style>